﻿#include "asycipc/inmemory_transport.hpp"

#include <chrono>

namespace asycipc {

InMemoryPipeHandle::InMemoryPipeHandle(
    std::shared_ptr<std::queue<std::vector<uint8_t>>> inbox,
    std::shared_ptr<std::queue<std::vector<uint8_t>>> outbox,
    std::shared_ptr<std::mutex> mutex,
    std::shared_ptr<std::condition_variable> cv)
    : inbox_(std::move(inbox)),
      outbox_(std::move(outbox)),
      mutex_(std::move(mutex)),
      cv_(std::move(cv)) {}

void InMemoryPipeHandle::Write(const std::vector<uint8_t>& data) {
  {
    std::lock_guard<std::mutex> lock(*mutex_);
    outbox_->push(data);
  }
  cv_->notify_all();
}

std::vector<uint8_t> InMemoryPipeHandle::Read() {
  std::unique_lock<std::mutex> lock(*mutex_);
  cv_->wait(lock, [&] { return !inbox_->empty(); });
  auto data = inbox_->front();
  inbox_->pop();
  return data;
}

InMemoryPipePair::InMemoryPipePair()
    : a_to_b_(std::make_shared<std::queue<std::vector<uint8_t>>>()),
      b_to_a_(std::make_shared<std::queue<std::vector<uint8_t>>>()),
      mutex_(std::make_shared<std::mutex>()),
      cv_(std::make_shared<std::condition_variable>()) {}

PipeHandlePtr InMemoryPipePair::ServerHandle() {
  return std::make_unique<InMemoryPipeHandle>(a_to_b_, b_to_a_, mutex_, cv_);
}

PipeHandlePtr InMemoryPipePair::ClientHandle() {
  return std::make_unique<InMemoryPipeHandle>(b_to_a_, a_to_b_, mutex_, cv_);
}

}  // namespace asycipc
